#include "SceneObject.h"
#include "Weapon.h"
#include "Projectile.h"
#include "Ship.h"
#include "MemoryStream.h"
#include "GameManager.h"

#include "NuclearMissile.h"
#include "LaserheadMissile.h"
#include "CounterMissile.h"

/*
	CShip deserializers													
*/
OBJSTRMAP CShip::deserializeShipTypeList(char *file) {
	CMemoryStream *stream;
	OBJSTRMAP ret;
	stream = new CMemoryStream(file);
	ret = CShip::deserializeShipTypeList(stream);

	delete stream;
	return ret;
}
OBJSTRMAP CShip::deserializeShipTypeList(char *buffer, long length) {
	CMemoryStream *stream;
	OBJSTRMAP ret;

	stream = new CMemoryStream(buffer, length);
	ret = CShip::deserializeShipTypeList(stream);

	delete stream;
	return ret;
}
OBJSTRMAP CShip::deserializeShipTypeList(irr::io::IFileReadCallBack *file) {
	OBJSTRMAP ret;
	CShip *ptr = NULL;

	DECLARE_XML_LIST(shipType)
	BEGIN_XML_READ(reader, file)
		BEGIN_XML_LIST(shipType)
			// toplevel section parse
			BEGIN_XML_NODE_READ()
			BEGIN_XML_NODE("acceleration")
				XML_ATTRIBUTE_SET(Float, ptr, MaxNormalAcceleration)
				XML_ATTRIBUTE_SET(Float, ptr, MaxHyperAcceleration)	
			END_XML_NODE()
			BEGIN_XML_NODE("id")
				if(ptr == NULL) 
					ptr = new CShip();
				BEGIN_XML_DATA()
					ptr->setXmlID(XML_DATA());
				END_XML_DATA()
			END_XML_NODE()
			BEGIN_XML_NODE("name")
				BEGIN_XML_DATA()
					ptr->setName(XML_DATA());
				END_XML_DATA()
			END_XML_NODE()  
			BEGIN_XML_NODE("class")
				BEGIN_XML_DATA()
					ptr->setClass(XML_DATA());
				END_XML_DATA()
			END_XML_NODE() 
			BEGIN_XML_NODE("model")
				BEGIN_XML_DATA()
				ptr->setMeshPath(XML_DATA());
				END_XML_DATA()
			END_XML_NODE()   
			BEGIN_XML_NODE("mass")
				BEGIN_XML_DATA()
					char *mass = XML_DATA();
					ptr->setMass((f32)atof(mass));
					free(mass);
				END_XML_DATA()
			END_XML_NODE()  
			BEGIN_XML_NODE("crew")
				ptr->setCrewCapacity(SCrewCapacity(XML_ATTRIBUTE(Int, officers), XML_ATTRIBUTE(Int, enlisted)));
			END_XML_NODE()   
			BEGIN_XML_NODE("sidewall")
				SArmor armor;
				armor.left = XML_ATTRIBUTE(Float, "left");
				armor.right = XML_ATTRIBUTE(Float, "right");
				armor.front = XML_ATTRIBUTE(Float, "front");
				armor.back = XML_ATTRIBUTE(Float, "back");
				armor.regen = XML_ATTRIBUTE(Float, "regen");
				ptr->setSidewallArmor(armor);
			END_XML_NODE()  
			BEGIN_XML_NODE("hull")
				SArmor armor;
				armor.left = XML_ATTRIBUTE(Float, "left");
				armor.right = XML_ATTRIBUTE(Float, "right");
				armor.front = XML_ATTRIBUTE(Float, "front");
				armor.back = XML_ATTRIBUTE(Float, "back");
				armor.regen = XML_ATTRIBUTE(Float, "regen");
				ptr->setHullArmor(armor);
			END_XML_NODE()  
			BEGIN_XML_NODE("dimensions")
				vector3df dim;
				dim.X = XML_ATTRIBUTE(Float, "height");
				dim.Y = XML_ATTRIBUTE(Float, "beam");
				dim.Z = XML_ATTRIBUTE(Float, "length");
				ptr->setDimensions(dim);
			END_XML_NODE() 
			BEGIN_XML_NODE("weapon")
				OBJSTRMAP weaponList = CGameManager::getInstance()->getWeaponTypes();
				
				
				OBJSTRMAP::iterator iter;
				for(iter=weaponList.begin();iter !=weaponList.end(); iter++) 
						if(!stricmp(iter->second->getXmlID(), reader->getAttributeValue("type")))
							break;
				if(iter != weaponList.end()) {
					int weaponCount = 0;
					weaponCount = reader->getAttributeValueAsInt("broadside");
					for(int weaponIndex=0;weaponIndex<weaponCount;weaponIndex++){
						CWeapon *weaponPtr = (CWeapon *)iter->second;
						weaponPtr = weaponPtr->copy();
						weaponPtr->setMountPoint(E_WEAPON_MOUNTPOINT::Left);
						weaponPtr->setParent(ptr);
						ptr->addWeapon(weaponPtr);
						
					}
					for(int weaponIndex=0;weaponIndex<weaponCount;weaponIndex++){
						CWeapon *weaponPtr = (CWeapon *)iter->second;
						weaponPtr = weaponPtr->copy();
						weaponPtr->setMountPoint(E_WEAPON_MOUNTPOINT::Right);
						weaponPtr->setParent(ptr);
						ptr->addWeapon(weaponPtr);
					}
					

					weaponCount = 0;
					weaponCount = reader->getAttributeValueAsInt("forward");
					for(int weaponIndex=0;weaponIndex<weaponCount;weaponIndex++){
						CWeapon *weaponPtr = (CWeapon *)iter->second;
						weaponPtr = weaponPtr->copy();
						weaponPtr->setMountPoint(E_WEAPON_MOUNTPOINT::Front);
						weaponPtr->setParent(ptr);
						ptr->addWeapon(weaponPtr);
					}

					weaponCount = 0;
					weaponCount = reader->getAttributeValueAsInt("aft");
					for(int weaponIndex=0;weaponIndex<weaponCount;weaponIndex++){
						CWeapon *weaponPtr = (CWeapon *)iter->second;
						weaponPtr = weaponPtr->copy();
						weaponPtr->setMountPoint(E_WEAPON_MOUNTPOINT::Back);
						weaponPtr->setParent(ptr);
						ptr->addWeapon(weaponPtr);
					}
				}
			END_XML_NODE()
		END_XML_LIST(shipType)
		BEGIN_FINALIZE_XML_LIST_ITEM(shipType)
			if(ptr)
				ret.insert(OBJSTRPAIR(ptr->getXmlID(), ptr));

			ptr = NULL;
		END_FINALIZE_XML_LIST_ITEM(shipType)
	END_XML_READ()

	return ret;
}


/*
	CProjectile deserializers													
*/
OBJSTRMAP CProjectile::deserializeProjectileTypeList(char *file) {
	CMemoryStream *stream;
	OBJSTRMAP ret;
	stream = new CMemoryStream(file);
	ret = CProjectile::deserializeProjectileTypeList(stream);

	delete stream;
	return ret;
}
OBJSTRMAP CProjectile::deserializeProjectileTypeList(char *buffer, long length) {
	CMemoryStream *stream;
	OBJSTRMAP ret;

	stream = new CMemoryStream(buffer, length);
	ret = CProjectile::deserializeProjectileTypeList(stream);

	delete stream;
	return ret;
}
OBJSTRMAP CProjectile::deserializeProjectileTypeList(irr::io::IFileReadCallBack *file) {
		OBJSTRMAP ret;
	CProjectile *ptr = NULL;

	DECLARE_XML_LIST(projectileType)
	BEGIN_XML_READ(reader, file)
		BEGIN_XML_LIST(projectileType)
			// toplevel section parse
			BEGIN_XML_NODE_READ()
			BEGIN_XML_NODE("acceleration")
				XML_ATTRIBUTE_SET(Float, ptr, MaxNormalAcceleration)
				XML_ATTRIBUTE_SET(Float, ptr, MaxHyperAcceleration)	
			END_XML_NODE()
			BEGIN_XML_NODE("id")
				BEGIN_XML_DATA()
					ptr->setXmlID(XML_DATA());
				END_XML_DATA()
			END_XML_NODE()
			BEGIN_XML_NODE("name")
				BEGIN_XML_DATA()
					ptr->setName(XML_DATA());
				END_XML_DATA()
			END_XML_NODE()  
			BEGIN_XML_NODE("class")
				BEGIN_XML_DATA()
					ptr->setClass(XML_DATA());
				END_XML_DATA()
			END_XML_NODE() 
			BEGIN_XML_NODE("model")
				BEGIN_XML_DATA()
				ptr->setMeshPath(XML_DATA());
				END_XML_DATA()
			END_XML_NODE()   
			BEGIN_XML_NODE("mass")
				BEGIN_XML_DATA()
					char *mass = XML_DATA();
					ptr->setMass((f32)atof(mass));
					free(mass);
				END_XML_DATA()
			END_XML_NODE()  
			BEGIN_XML_NODE("baseDamage")
				BEGIN_XML_DATA()
				char *dmg = XML_DATA();
				ptr->setBaseDamage((f32)atof(dmg));
				free(dmg);
				END_XML_DATA()
			END_XML_NODE()
			BEGIN_XML_NODE("StandoffRange")
				BEGIN_XML_DATA()
				char *dmg = XML_DATA();
				ptr->setStandoffRange((f32)atof(dmg));
				free(dmg);
				END_XML_DATA()
			END_XML_NODE()  
			BEGIN_XML_NODE("sidewall")
				SArmor armor;
				armor.left = XML_ATTRIBUTE(Float, "left");
				armor.right = XML_ATTRIBUTE(Float, "right");
				armor.front = XML_ATTRIBUTE(Float, "front");
				armor.back = XML_ATTRIBUTE(Float, "back");
				armor.regen = XML_ATTRIBUTE(Float, "regen");
				ptr->setSidewallArmor(armor);
			END_XML_NODE()  
			BEGIN_XML_NODE("hull")
				SArmor armor;
				armor.left = XML_ATTRIBUTE(Float, "left");
				armor.right = XML_ATTRIBUTE(Float, "right");
				armor.front = XML_ATTRIBUTE(Float, "front");
				armor.back = XML_ATTRIBUTE(Float, "back");
				armor.regen = XML_ATTRIBUTE(Float, "regen");
				ptr->setHullArmor(armor);
			END_XML_NODE()  
			BEGIN_XML_NODE("dimensions")
				vector3df dim;
				dim.X = XML_ATTRIBUTE(Float, "height");
				dim.Y = XML_ATTRIBUTE(Float, "beam");
				dim.Z = XML_ATTRIBUTE(Float, "length");
				ptr->setDimensions(dim);
			END_XML_NODE() 
		END_XML_LIST(projectileType)
		BEGIN_FINALIZE_XML_LIST_ITEM(projectileType)
			if(ptr) 	
				ret.insert(OBJSTRPAIR(ptr->getXmlID(), ptr));
			
			ptr = new CProjectile();
		END_FINALIZE_XML_LIST_ITEM(projectileType)
	END_XML_READ()

	return ret;
}
/*
	CWeapon deserializers													
*/
OBJSTRMAP CWeapon::deserializeWeaponTypeList(char *file) {
	CMemoryStream *stream;
	OBJSTRMAP ret;
	stream = new CMemoryStream(file);
	ret = CWeapon::deserializeWeaponTypeList(stream);

	delete stream;
	return ret;
}
OBJSTRMAP CWeapon::deserializeWeaponTypeList(char *buffer, long length) {
	CMemoryStream *stream;
	OBJSTRMAP ret;

	stream = new CMemoryStream(buffer, length);
	ret = CWeapon::deserializeWeaponTypeList(stream);

	delete stream;
	return ret;
}
OBJSTRMAP CWeapon::deserializeWeaponTypeList(irr::io::IFileReadCallBack *file) {
	OBJSTRMAP ret;
	CWeapon *ptr = NULL;

	DECLARE_XML_LIST(weaponType)
	BEGIN_XML_READ(reader, file)
		BEGIN_XML_LIST(weaponType)
			// toplevel section parse
			BEGIN_XML_NODE_READ()
			BEGIN_XML_NODE("id")
				BEGIN_XML_DATA()
					ptr->setXmlID(XML_DATA());
				END_XML_DATA()
			END_XML_NODE()
			BEGIN_XML_NODE("name")
				BEGIN_XML_DATA()
					ptr->setName(XML_DATA());
				END_XML_DATA()
			END_XML_NODE()
			BEGIN_XML_NODE("projectileId")
				BEGIN_XML_DATA()
					ptr->setProjectileID(XML_DATA());
					OBJSTRMAP projList = CGameManager::getInstance()->getProjectileTypes();
					OBJSTRMAP::iterator iter;
					// set its projectile ptr based on ID
					for(iter=projList.begin();iter !=projList.end(); iter++) 
						if(!stricmp(iter->first, ptr->getProjectileID()))
							break;
					if(iter != projList.end())
						ptr->setProjectile((CProjectile*)iter->second);
				END_XML_DATA()
			END_XML_NODE()  
			// TODO: ADD MOUNTPOINT 
			BEGIN_XML_NODE("class")
				BEGIN_XML_DATA()
					ptr->setClass(XML_DATA());
				END_XML_DATA()
			END_XML_NODE()  
		END_XML_LIST(weaponType)
		BEGIN_FINALIZE_XML_LIST_ITEM(weaponType)
			if(ptr)
				ret.insert(OBJSTRPAIR(ptr->getXmlID(), ptr));

			ptr = new CWeapon();
		END_FINALIZE_XML_LIST_ITEM(weaponType)
	END_XML_READ()

	return ret;
}
/*
	CSceneObject deserializers													
*/
void CSceneObject::deserialize(char *file) {
	CMemoryStream *stream;

	stream = new CMemoryStream(file);
	deserialize(stream);

	delete stream;
}
void CSceneObject::deserialize(char *buffer, long length) {
	CMemoryStream *stream;

	stream = new CMemoryStream(buffer, length);
	deserialize(stream);

	delete stream;
}
void CSceneObject::deserialize(IFileReadCallBack *file) {
	IrrXMLReader* reader = createIrrXMLReader(file);
	
	while(reader && reader->read()) {
		switch(reader->getNodeType()) {
			case EXN_ELEMENT:
				char *foo = (char *) reader->getNodeName();	
				if (!stricmp("object", reader->getNodeName())) {
					this->setAcceleration(reader->getAttributeValueAsFloat("acceleration"));
					this->setVelocity(getStringVector((char *)reader->getAttributeValue("heading")));
					this->setPosition(getStringVector((char *)reader->getAttributeValue("position")));
					break;
				} 
				if(!stricmp("objectList", reader->getNodeName())) {
					
				}

				break;
		}
	}

	delete reader;
}